package org.oep.jmingle;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import javax.microedition.rms.RecordStoreException;

public class MingleTracker {
	// private JMingle parent;
	
	private final String defaultName = "???";
	private final String recordName = "MingleDB";
	private final Hashtable mingledDevices;
	private Vector lastScan;
	private Vector thisScan;
	
	public MingleTracker(JMingle parent) {
		thisScan = new Vector();
		lastScan = new Vector();
		mingledDevices = new Hashtable();
	}
	
	
	/*
	 * For external use
	 */
	//--------------------------------------------------------------//
	
	public int numberOfDevices() {
		if(mingledDevices != null)
			return mingledDevices.size();
		else
			return -1;
	}
	
	public MingleNode deviceAt(int a) {
		//TODO: This is slow! Find a better way to do it
		if(a < 0 || a >= mingledDevices.size())
			throw new IllegalArgumentException("Index out of range");
		
		Enumeration e = mingledDevices.elements();
		
		int i = 0;
		while(e.hasMoreElements()) {
			if(a == i) return (MingleNode) e.nextElement();
			else e.nextElement();
			i++;
		}
		
		throw new IllegalArgumentException("Index out of range");
	}
	
	public int countSavedDevices() {
		try {
			return RecordStoreTools.countRecords(recordName);
		}
		catch(RecordStoreException e) {
			return -1;
		}
	}
	
	public Enumeration getDevices() {
		return mingledDevices.elements();
	}
	
	public void exportToRecordStore() {
		try {
			RecordStoreTools.export(mingledDevices, recordName);
		}
		catch(Exception e) {
			
		}
	}
	
	public void doLoad() {
		if(mingledDevices == null) {
			System.out.println("NULL OMG");
		}
		try {
			RecordStoreTools.load(recordName, mingledDevices);
		} catch (RecordStoreException e) {
			mingledDevices.clear();
		}
	}
	
	public void doMingle(Actor a) {
		doMingle(a.getAddress(), a.getOwner());
	}
	
	public void doMingle(String address, String name) {
		// Fix the default name
		if(name == null)
			name = defaultName;
		if(name.length() == 0)
			name = defaultName;
		
		long time = -1;
		MingleNode node = null;
		
		// Here, this device is not new to us
		if(mingledDevices.containsKey(address)){
			boolean updated = false;
			node = (MingleNode) mingledDevices.get(address);
			time = node.getLastSeen();
			node.markSeen();
			
			// In this case, we've seen it before, but it's name has changed
			if( shouldDoUpdate(node.getName(), name) ) {
				node.setName(name);
				try {
					if(RecordStoreTools.update(node, recordName)) {
						updated = true;
						// parent.tell("Updated: " + oldName + " -> " + name);
					}
				}
				catch (RecordStoreException e) {
					// parent.tell(e.toString());
				}
			}
			
			node.bump();
			if(time > 0)
				// parent.tell("Seen " + Utils.friendlyTimeDiffNow(time) + " ago");
			
			// This is to update the time if it hasn't been already
			try {
				if(!updated)
					RecordStoreTools.update(node, recordName);
			}
			catch(RecordStoreException e) {
				// parent.tell( e.toString() );
			}
				
			
		}
		
		// It's brand-spanking new
		else {
			node = new MingleNode(name, address);
			node.bump();
			mingledDevices.put(address, node);
			
			// Add it to the Record Store
			try {
				RecordStoreTools.add(node, recordName);
				// parent.tell("Saved: " + name);
			}
			catch(RecordStoreException e) {
				// parent.tell(e.toString());
			}
		}

	}
	
	public void eraseAll() {
		mingledDevices.clear();
		thisScan.removeAllElements();
		lastScan.removeAllElements();
		// parent.tell("Deleted mingles in memory");
		try {
			RecordStoreTools.delete(recordName);
		//	parent.tell("Deleted saved mingles");
		}
		catch(RecordStoreException e) {
		//	parent.tell(e.getMessage());
		}
	}
	
	public boolean know(Actor a) {
		return know(a.getAddress());
	}
	
	public boolean know(String address) {
		return mingledDevices.containsKey( address );
	}
	
	public String getLastSeenTime(Actor a) throws Exception {
		return getLastSeenTime(a.getAddress());
	}
	
	public String getLastSeenTime(String address) throws Exception {
		MingleNode n = (MingleNode) mingledDevices.get(address);
		
		if(n == null) throw new Exception("No such key");
		
		return Utils.friendlyTimeDiffNow( n.getLastSeen() );
	}
	
	public long getRawLastSeenTime(String address) throws Exception {
		MingleNode n = (MingleNode) mingledDevices.get(address);
		
		if(n == null) throw new Exception("No such key");
		System.out.println("Raw time of: " + n.getLastSeen());
		return n.getLastSeen();
	}
	
	public MingleNode getNode(String hash) {
		return (MingleNode) mingledDevices.get(hash);
	}

	private boolean shouldDoUpdate(String o, String n) {
		// Never update to the default name
		if(n.compareTo(defaultName) == 0) return false;
		
		// Never update if names are the same
		if(o.compareTo(n) == 0) return false;
		
		return true;
	}
}
